package com.example.auth.controller;

import com.example.auth.annotation.RequireRole;
import com.example.auth.dto.TaskDTO;
import com.example.auth.dto.TaskEvaluationDTO;
import com.example.auth.dto.ProjectEvaluationDTO;
import com.example.auth.dto.ProjectDTO;
import com.example.auth.dto.TaskSubmissionDTO;
import com.example.auth.entity.User;
import com.example.auth.service.TaskEvaluationService;
import com.example.auth.service.ProjectEvaluationService;
import com.example.auth.service.ProjectService;
import com.example.auth.service.TaskService;
import com.example.auth.service.TaskSubmissionService;
import com.example.auth.service.UserService;
import com.example.auth.util.JwtUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api")
public class TaskSubmissionController {

    private static final Logger logger = LoggerFactory.getLogger(TaskSubmissionController.class);

    @Autowired
    private TaskSubmissionService taskSubmissionService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private UserService userService;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private TaskEvaluationService taskEvaluationService;

    @Autowired
    private ProjectEvaluationService projectEvaluationService;

    @Autowired
    private ProjectService projectService;

    @PostMapping("/user/tasks/{taskId}/submit")
    @RequireRole("USER")
    public ResponseEntity<?> submitTaskFile(
            @PathVariable Long taskId,
            @RequestParam("file") MultipartFile file,
            @RequestParam(value = "comment", required = false) String comment,
            @RequestHeader("Authorization") String auth) {

        try {
            // Get the current user
            String token = auth.substring(7); // Remove "Bearer " prefix
            String username = jwtUtil.getUsernameFromToken(token);
            User user = userService.findByUsername(username);

            if (user == null) {
                logger.error("Failed to submit task file: User does not exist, Task ID: {}", taskId);
                return ResponseEntity.badRequest().body(Map.of("message", "User does not exist"));
            }

            logger.info("User submitting task file, User ID: {}, Task ID: {}, Filename: {}", user.getId(), taskId, file.getOriginalFilename());

            // Check if the task exists
            TaskDTO task;
            try {
                task = taskService.getTaskById(taskId);
                logger.info("Task retrieval successful, Task ID: {}, Assigned to User ID: {}, Supervisor ID: {}, Current User ID: {}",
                        taskId, task.getAssigneeId(), task.getSupervisorId(), user.getId());
            } catch (Exception e) {
                logger.error("Failed to submit task file: Task does not exist, Task ID: {}", taskId);
                return ResponseEntity.badRequest().body(Map.of("message", "Task does not exist"));
            }

            // Verify task submission permissions
            // Allow three cases: 1. User is the task's assignee 2. assigneeId is null and user is the task's supervisor 3. User is the task's supervisor
            boolean hasAccess = false;
            if (task.getAssigneeId() != null && user.getId().equals(task.getAssigneeId())) {
                // User is the task's assignee
                hasAccess = true;
                logger.info("User is the task's assigned student, submission allowed, User ID: {}, Task ID: {}", user.getId(), taskId);
            } else if (task.getAssigneeId() == null && user.getId().equals(task.getSupervisorId())) {
                // assigneeId is null and user is the task's supervisor
                hasAccess = true;
                logger.info("Task is not assigned to any student, but the user is the task's supervisor, submission allowed, User ID: {}, Task ID: {}", user.getId(), taskId);
            } else if (user.getId().equals(task.getSupervisorId())) {
                // User is the task's supervisor
                hasAccess = true;
                logger.info("User is the task's supervisor, submission allowed, User ID: {}, Task ID: {}", user.getId(), taskId);
            }

            if (!hasAccess) {
                logger.error("Failed to submit task file: No permission to submit this task, Task ID: {}, Task assigned to User ID: {}, Task Supervisor ID: {}, Current User ID: {}",
                        taskId, task.getAssigneeId(), task.getSupervisorId(), user.getId());
                return ResponseEntity.badRequest().body(Map.of("message", "No permission to submit this task"));
            }

            // Submit the task file
            TaskSubmissionDTO submissionDTO = taskSubmissionService.submitTaskFile(taskId, file, user.getId(), comment);
            logger.info("Task file submission successful, Task ID: {}, User ID: {}, Submission ID: {}",
                    taskId, user.getId(), submissionDTO.getId());

            return ResponseEntity.ok(submissionDTO);
        } catch (Exception e) {
            logger.error("Failed to submit task file, Task ID: {}, Error: {}", taskId, e.getMessage(), e);
            return ResponseEntity.badRequest().body(Map.of("message", "Failed to submit task file: " + e.getMessage()));
        }
    }

    /**
     * Get task submission records
     */
    @GetMapping("/tasks/{taskId}/submissions")
    public ResponseEntity<?> getTaskSubmissions(
            @PathVariable Long taskId,
            @RequestHeader("Authorization") String auth) {

        try {
            // Get the current user
            String token = auth.substring(7);
            String username = jwtUtil.getUsernameFromToken(token);
            User user = userService.findByUsername(username);

            if (user == null) {
                return ResponseEntity.badRequest().body(Map.of("message", "User does not exist"));
            }

            // Get task submission records (directly pass the user ID to the service layer for permission filtering)
            List<TaskSubmissionDTO> submissions = taskSubmissionService.getSubmissionsByTaskId(taskId, user.getId());

            return ResponseEntity.ok(submissions);
        } catch (Exception e) {
            logger.error("Failed to get task submission records", e);
            return ResponseEntity.badRequest().body(Map.of("message", "Failed to get task submission records: " + e.getMessage()));
        }
    }

    /**
     * Get submission details
     */
    @GetMapping("/submissions/{submissionId}")
    public ResponseEntity<?> getSubmissionDetail(
            @PathVariable Long submissionId,
            @RequestHeader("Authorization") String auth) {

        try {
            // Get the current user
            String token = auth.substring(7);
            String username = jwtUtil.getUsernameFromToken(token);
            User user = userService.findByUsername(username);

            if (user == null) {
                return ResponseEntity.badRequest().body(Map.of("message", "User does not exist"));
            }

            // Get submission details
            TaskSubmissionDTO submission = taskSubmissionService.getSubmissionById(submissionId);

            // Check permissions (the task's supervisor or submitter can view)
            Long taskId = submission.getTaskId();
            TaskDTO task = taskService.getTaskById(taskId);
            boolean isSupervisor = task.getSupervisorId().equals(user.getId());
            boolean isAssignee = task.getAssigneeId() != null && task.getAssigneeId().equals(user.getId());
            
            // Check if user is a project supervisor
            boolean isProjectSupervisor = false;
            if (task.getProjectId() != null) {
                try {
                    isProjectSupervisor = projectService.isUserProjectSupervisor(task.getProjectId(), user.getId());
                    logger.info("Checking if user is project supervisor: User ID={}, Project ID={}, Result={}", 
                            user.getId(), task.getProjectId(), isProjectSupervisor);
                } catch (Exception e) {
                    logger.warn("Error checking project supervisor status: {}", e.getMessage());
                }
            }

            if (!isSupervisor && !isAssignee && !isProjectSupervisor) {
                logger.warn("User has no permission to view this submission, User ID: {}, Submission ID: {}, Task ID: {}", 
                        user.getId(), submissionId, taskId);
                return ResponseEntity.badRequest().body(Map.of("message", "No permission to view this submission"));
            }

            return ResponseEntity.ok(submission);
        } catch (Exception e) {
            logger.error("Failed to get submission details", e);
            return ResponseEntity.badRequest().body(Map.of("message", "Failed to get submission details: " + e.getMessage()));
        }
    }

    /**
     * Delete submission record
     */
    @DeleteMapping("/user/submissions/{submissionId}")
    @RequireRole("USER")
    public ResponseEntity<?> deleteSubmission(
            @PathVariable Long submissionId,
            @RequestHeader("Authorization") String auth) {

        try {
            // Get the current user
            String token = auth.substring(7);
            String username = jwtUtil.getUsernameFromToken(token);
            User user = userService.findByUsername(username);

            if (user == null) {
                return ResponseEntity.badRequest().body(Map.of("message", "User does not exist"));
            }

            // Get submission details
            TaskSubmissionDTO submission = taskSubmissionService.getSubmissionById(submissionId);

            // Check if the user is the submitter
            if (!submission.getSubmitterId().equals(user.getId())) {
                return ResponseEntity.badRequest().body(Map.of("message", "No permission to delete this submission record"));
            }

            // Delete submission record
            boolean deleted = taskSubmissionService.deleteSubmission(submissionId);

            if (deleted) {
                return ResponseEntity.ok(Map.of("message", "Submission record deleted successfully"));
            } else {
                return ResponseEntity.badRequest().body(Map.of("message", "Failed to delete submission record"));
            }
        } catch (Exception e) {
            logger.error("Failed to delete submission record", e);
            return ResponseEntity.badRequest().body(Map.of("message", "Failed to delete submission record: " + e.getMessage()));
        }
    }

    /**
     * Update submission comment
     */
    @PutMapping("/user/submissions/{submissionId}/comment")
    @RequireRole("USER")
    public ResponseEntity<?> updateSubmissionComment(
            @PathVariable Long submissionId,
            @RequestBody Map<String, String> commentData,
            @RequestHeader("Authorization") String auth) {

        String comment = commentData.get("comment");

        try {
            // Get the current user
            String token = auth.substring(7);
            String username = jwtUtil.getUsernameFromToken(token);
            User user = userService.findByUsername(username);

            if (user == null) {
                return ResponseEntity.badRequest().body(Map.of("message", "User does not exist"));
            }

            // Get submission details
            TaskSubmissionDTO submission = taskSubmissionService.getSubmissionById(submissionId);

            // Check if the user is the submitter
            if (!submission.getSubmitterId().equals(user.getId())) {
                return ResponseEntity.badRequest().body(Map.of("message", "No permission to update this submission comment"));
            }

            // Update submission comment
            TaskSubmissionDTO updatedSubmission = taskSubmissionService.updateSubmissionComment(submissionId, comment);

            return ResponseEntity.ok(updatedSubmission);
        } catch (Exception e) {
            logger.error("Failed to update submission comment", e);
            return ResponseEntity.badRequest().body(Map.of("message", "Failed to update submission comment: " + e.getMessage()));
        }
    }

    /**
     * View all submission records of the user
     */
    @GetMapping("/user/submissions")
    @RequireRole("USER")
    public ResponseEntity<?> getUserSubmissions(@RequestHeader("Authorization") String auth) {
        try {
            // Get the current user
            String token = auth.substring(7);
            String username = jwtUtil.getUsernameFromToken(token);
            User user = userService.findByUsername(username);

            if (user == null) {
                return ResponseEntity.badRequest().body(Map.of("message", "User does not exist"));
            }

            // Get user submission records
            List<TaskSubmissionDTO> submissions = taskSubmissionService.getSubmissionsBySubmitterId(user.getId());

            return ResponseEntity.ok(submissions);
        } catch (Exception e) {
            logger.error("Failed to get user submission records", e);
            return ResponseEntity.badRequest().body(Map.of("message", "Failed to get user submission records: " + e.getMessage()));
        }
    }

    /**
     * Update task completion status
     */
    @PutMapping("/tasks/{taskId}/completion")
    public ResponseEntity<?> updateTaskCompletionStatus(
            @PathVariable Long taskId,
            @RequestBody Map<String, Boolean> completionData,
            @RequestHeader("Authorization") String auth) {
        Boolean completed = completionData.get("completed");

        try {
            if (completed == null) {
                return ResponseEntity.badRequest().body(Map.of("message", "Missing completion status parameter"));
            }

            // Get the current user
            String token = auth.substring(7);
            String username = jwtUtil.getUsernameFromToken(token);
            User user = userService.findByUsername(username);

            if (user == null) {
                return ResponseEntity.badRequest().body(Map.of("message", "User does not exist"));
            }

            logger.info("User requested to update task completion status, User ID: {}, Task ID: {}, Completion status: {}", user.getId(), taskId, completed);

            // Get task details
            TaskDTO task = taskService.getTaskById(taskId);

            // Verify if the task is assigned to the current user or is a supervisor
            if (!user.getId().equals(task.getAssigneeId()) && !user.getId().equals(task.getSupervisorId())) {
                return ResponseEntity.badRequest().body(Map.of("message", "No permission to update this task"));
            }

            // Update task completion status
            TaskDTO updatedTask = taskService.updateTaskCompletionStatus(taskId, completed);
            return ResponseEntity.ok(updatedTask);
        } catch (Exception e) {
            logger.error("Failed to update task completion status, Task ID: {}, Error: {}", taskId, e.getMessage(), e);
            return ResponseEntity.badRequest().body(Map.of("message", "Failed to update task completion status: " + e.getMessage()));
        }
    }

    /**
     * Supervisor download submission file
     */
    @GetMapping("/submissions/{submissionId}/download")
    public ResponseEntity<?> downloadSubmissionFile(
            @PathVariable Long submissionId,
            @RequestHeader("Authorization") String auth) {

        try {
            // Get the current user
            String token = auth.substring(7);
            String username = jwtUtil.getUsernameFromToken(token);
            User user = userService.findByUsername(username);

            if (user == null) {
                return ResponseEntity.badRequest().body(Map.of("message", "User does not exist"));
            }

            // Get submission details
            TaskSubmissionDTO submission = taskSubmissionService.getSubmissionById(submissionId);
            Long taskId = submission.getTaskId();
            
            // Get task information, check permissions
            TaskDTO task = taskService.getTaskById(taskId);
            boolean isSupervisor = task.getSupervisorId().equals(user.getId());
            boolean isAssignee = task.getAssigneeId() != null && task.getAssigneeId().equals(user.getId());
            boolean isProjectSupervisor = false;
            
            if (task.getProjectId() != null) {
                try {
                    isProjectSupervisor = projectService.isUserProjectSupervisor(task.getProjectId(), user.getId());
                    logger.info("Checking if user is project supervisor: User ID={}, Project ID={}, Result={}", 
                            user.getId(), task.getProjectId(), isProjectSupervisor);
                } catch (Exception e) {
                    logger.warn("Error checking project supervisor status: {}", e.getMessage());
                }
            }

            if (!isSupervisor && !isAssignee && !isProjectSupervisor) {
                logger.warn("User has no permission to download this submission file, User ID: {}, Submission ID: {}, Task ID: {}", 
                        user.getId(), submissionId, taskId);
                return ResponseEntity.badRequest().body(Map.of("message", "No permission to download this submission file"));
            }

            try {
                // Use the file path from the submission record
                String filePath = submission.getFilePath();
                logger.info("Attempting to download file, file path: {}", filePath);
                
                // Get file resource
                Resource resource = taskSubmissionService.loadFileAsResource(filePath);
                
                // Get MIME type
                String contentType = submission.getFileType();
                if (contentType == null || contentType.isEmpty()) {
                    contentType = "application/octet-stream";
                }
                
                // Return file response
                return ResponseEntity.ok()
                        .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + submission.getOriginalFilename() + "\"")
                        .contentType(MediaType.parseMediaType(contentType))
                        .body(resource);
            } catch (Exception e) {
                logger.error("File download failed: {}", e.getMessage(), e);
                return ResponseEntity.badRequest().body(Map.of(
                    "message", "Failed to download file \"" + submission.getOriginalFilename() + "\": " + e.getMessage()
                ));
            }
        } catch (Exception e) {
            logger.error("Download file failed", e);
            return ResponseEntity.badRequest().body(Map.of("message", "Download file failed: " + e.getMessage()));
        }
    }

    /**
     * Student download submission file
     */
    @GetMapping("/user/submissions/{submissionId}/download")
    @RequireRole("USER")
    public ResponseEntity<?> downloadUserSubmissionFile(
            @PathVariable Long submissionId,
            @RequestHeader("Authorization") String auth) {

        try {
            // Get the current user
            String token = auth.substring(7);
            String username = jwtUtil.getUsernameFromToken(token);
            User user = userService.findByUsername(username);

            if (user == null) {
                return ResponseEntity.badRequest().body(Map.of("message", "User does not exist"));
            }

            // Get submission details
            TaskSubmissionDTO submission = taskSubmissionService.getSubmissionById(submissionId);

            // Check download permissions
            boolean isSubmitter = submission.getSubmitterId().equals(user.getId());
            
            // Check if user is task supervisor or project supervisor
            TaskDTO task = taskService.getTaskById(submission.getTaskId());
            boolean isSupervisor = task.getSupervisorId().equals(user.getId());
            boolean isProjectSupervisor = false;
            
            if (task.getProjectId() != null) {
                try {
                    isProjectSupervisor = projectService.isUserProjectSupervisor(task.getProjectId(), user.getId());
                } catch (Exception e) {
                    logger.warn("Error checking project supervisor status: {}", e.getMessage());
                }
            }
            
            if (!isSubmitter && !isSupervisor && !isProjectSupervisor) {
                return ResponseEntity.badRequest().body(Map.of("message", "No permission to download this submission file"));
            }

            try {
                // Use the file path from the submission record
                String filePath = submission.getFilePath();
                logger.info("Student attempting to download file, file path: {}", filePath);
                
                // Get file resource
                Resource resource = taskSubmissionService.loadFileAsResource(filePath);
                
                // Get MIME type
                String contentType = submission.getFileType();
                if (contentType == null || contentType.isEmpty()) {
                    contentType = "application/octet-stream";
                }
                
                // Return file response
                return ResponseEntity.ok()
                        .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + submission.getOriginalFilename() + "\"")
                        .contentType(MediaType.parseMediaType(contentType))
                        .body(resource);
            } catch (Exception e) {
                logger.error("Student file download failed: {}", e.getMessage(), e);
                return ResponseEntity.badRequest().body(Map.of(
                    "message", "Failed to download file \"" + submission.getOriginalFilename() + "\": " + e.getMessage()
                ));
            }
        } catch (Exception e) {
            logger.error("Failed to download file", e);
            return ResponseEntity.badRequest().body(Map.of("message", "Failed to download file: " + e.getMessage()));
        }
    }

    /**
     * Student get task evaluation
     */
    @GetMapping("/user/tasks/{taskId}/evaluation")
    @RequireRole("USER")
    public ResponseEntity<?> getTaskEvaluationForStudent(
            @PathVariable Long taskId,
            @RequestHeader("Authorization") String auth) {

        logger.info("Student requested to get task evaluation, Task ID: {}", taskId);

        try {
            // Get the current user
            String token = auth.substring(7);
            String username = jwtUtil.getUsernameFromToken(token);
            User user = userService.findByUsername(username);

            if (user == null) {
                return ResponseEntity.badRequest().body(Map.of("message", "User does not exist"));
            }

            // Get task details
            TaskDTO task = taskService.getTaskById(taskId);

            // Check permissions (the task's student can view)
            boolean isAssignee = task.getAssigneeId() != null && task.getAssigneeId().equals(user.getId());
            if (!isAssignee) {
                return ResponseEntity.badRequest().body(Map.of("message", "Only the student assigned to the task can view the evaluation"));
            }

            // Check if the task is completed
            if (!task.getCompleted()) {
                return ResponseEntity.badRequest().body(Map.of("message", "Task is not yet completed, evaluation cannot be viewed"));
            }

            // Get evaluation
            TaskEvaluationDTO evaluation = taskEvaluationService.getEvaluationByTaskId(taskId);

            if (evaluation == null) {
                return ResponseEntity.ok(Map.of("message", "Task has not yet been evaluated"));
            }

            return ResponseEntity.ok(evaluation);
        } catch (Exception e) {
            logger.error("Failed to get task evaluation", e);
            return ResponseEntity.badRequest().body(Map.of("message", "Failed to get task evaluation: " + e.getMessage()));
        }
    }

    /**
     * Student get project evaluation
     */
    @GetMapping("/user/projects/{projectId}/evaluation")
    @RequireRole("USER")
    public ResponseEntity<?> getProjectEvaluationForStudent(
            @PathVariable Long projectId,
            @RequestHeader("Authorization") String auth) {

        logger.info("Student requested to get project evaluation, Project ID: {}", projectId);

        try {
            // Get the current user
            String token = auth.substring(7);
            String username = jwtUtil.getUsernameFromToken(token);
            User user = userService.findByUsername(username);

            if (user == null) {
                return ResponseEntity.badRequest().body(Map.of("message", "User does not exist"));
            }

            // Get project details
            ProjectDTO project = projectService.getProjectById(projectId);

            // Check permissions (the project's student can view)
            boolean isAssignee = project.getAssigneeId() != null && project.getAssigneeId().equals(user.getId());
            if (!isAssignee) {
                return ResponseEntity.badRequest().body(Map.of("message", "Only the student assigned to the project can view the evaluation"));
            }

            // Check if the project is completed
            if (!"Completed".equals(project.getStatus())) {
                return ResponseEntity.badRequest().body(Map.of("message", "Can only evaluate completed projects"));
            }

            // Get evaluation
            ProjectEvaluationDTO evaluation = projectEvaluationService.getEvaluationByProjectId(projectId);

            if (evaluation == null) {
                return ResponseEntity.ok(Map.of("message", "Project has not yet been evaluated"));
            }

            return ResponseEntity.ok(evaluation);
        } catch (Exception e) {
            logger.error("Failed to get project evaluation", e);
            return ResponseEntity.badRequest().body(Map.of("message", "Failed to get project evaluation: " + e.getMessage()));
        }
    }
}